﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Runtime.InteropServices;
using System.Xml;

//Add MySql Library
using MySql.Data.MySqlClient;

[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
struct IntFloatUnion
{
    [System.Runtime.InteropServices.FieldOffset(0)]
    public int ival;

    [System.Runtime.InteropServices.FieldOffset(0)]
    public float fval;
}

struct measurementData
{
    public int ontime;                     // seconds that the power is ON of plugmeter
    public IntFloatUnion V;
    public IntFloatUnion I;
    public IntFloatUnion P;
    public IntFloatUnion Q1;
    public IntFloatUnion S;
    public IntFloatUnion S1;
    public IntFloatUnion PF;
    public IntFloatUnion PF1;
    public IntFloatUnion SN;
    public IntFloatUnion N;
    public IntFloatUnion THDI;
    public IntFloatUnion Tplus;
    public IntFloatUnion Tminus;
}

struct plugmeterType
{
    public int uniqueId;                   // the unique number of the EM773 inside the plugmeter
 
    // info created by this Application
    public int plugmeterOffAirCnt;         // seconds counter since the last received measured data
    public bool plugmeterOnAir;            // false when no msg has been received from plugmeter within 'timeout' period
    public String name;
    public int rssi;

    // current settings in plugmeter
    public int mainsFrequency;             // mains frequency as measured by the plugmeter at power on
    public int transmitInterval;           // interval in seconds that plugmeter sends measured data
    public bool relayClosed;               // true when relay is closed
    public int hwVersion;                  // Uni(=1or2) or Bi(=3) directional Plugmeter
    public IntFloatUnion Vpp;              // Vpp  calibration value needed for metrology engine
    public IntFloatUnion I1pp;             // I1pp calibration value needed for metrology engine
    public IntFloatUnion I2pp;             // I2pp calibration value needed for metrology engine
    public IntFloatUnion Phi1;             // Phi1 calibration value needed for metrology engine
    public IntFloatUnion Phi2;             // Phi2 calibration value needed for metrology engine

    // measured data by plugmeter
    public measurementData md;
}

struct calibrationData
{
    public IntFloatUnion Vpp;
    public IntFloatUnion I1pp;
    public IntFloatUnion I2pp;
    public IntFloatUnion DeltaPhi1;
    public IntFloatUnion DeltaPhi2;
    public IntFloatUnion Vref;
    public IntFloatUnion I1ref;
    public IntFloatUnion I2ref;
}

namespace PlugMeterControl
{
    public partial class FormMain : Form
    {
        [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileString")]
        protected internal static extern int GetPrivateProfileString(string lpAppName,
                string lpKeyName, string lpDefault,
                StringBuilder lpReturnedString, int nSize,
                string lpFileName); 
        
        private plugmeterType[] pmArray = new plugmeterType[50];
        private int max_plug_meters = 50;

        static SerialPort firstSerialPort;
        private DateTime firstSerialPortOpenTime;
        private Thread firstSerialPortReadThread;
        private bool firstSerialThreadContinue = false;
        private bool CommunicateWithOldRfDongleSW = false;
        private bool dongleConnected = false;
        private int dongleUptimeSeconds = 0;
        private bool dutchNumberStyle = false;
        private bool numberEntered = false;
        private int numberOfPlugmeters = 8;  // Initial the View All tab shows 8 plugmeters
        private byte[] mbusDataBlock = new byte[16]; // Used to check CRCs of mbus data blocks, which are max 16 byte long
        private calibrationData CalibrationRef50Data;
        private calibrationData CalibrationRef60Data;
        private XmlDocument xmldoc;
        private String xmlFile = ".\\PlugMeterControl.xml";

        private MySqlConnection connection;
        private string server;
        private string database;
        private string uid;
        private string password;


        // *****************************************************************
        //                         Main Form entry point
        // *****************************************************************

        public FormMain(string[] args)
        {
            int i;
            StringBuilder tmpStr = new StringBuilder(16);

            foreach (string s in args)
            {
                // check startup parameters
                if ((s == "LF") || (s == "lf"))
                {
                    CommunicateWithOldRfDongleSW = true;
                }
            }
            InitializeComponent();
            InitPlugmeterArray();
            DialogErrorMsg = new FormErrorMsg();
            DialogAbout = new FormAbout();
            DialogOpenPort = new FormOpenPort();
            DialogCost = new FormCost();
            firstSerialPort = new SerialPort();
            DialogCalibration = new CalibrationForm(this);
            for (i = 0; i <= numberOfPlugmeters; i++)
            {
                dataGridViewAll.Rows.Add();
                if (i < numberOfPlugmeters)
                {
                    dataGridViewAll.Rows[i].Cells[0].Value = i + 1;
                    dataGridViewAll.Rows[i].Cells[1].Value = "";
                    dataGridViewAll.Rows[i].Cells[2].Value = "No";
                }
                else
                {
                    dataGridViewAll.Rows[i].Cells[0].Value = "";
                    dataGridViewAll.Rows[i].Cells[1].Value = "Total";
                    dataGridViewAll.Rows[i].Cells[2].Value = "0";
                }
            }
            ResetChartPowerUsage();
            // detect if float uses . or , as separator
            float ftest = (float)1.0 / 4;
            if (CountColonsInString(ftest.ToString()) > 0)
                dutchNumberStyle = true;

            xmldoc = new XmlDocument();
            try
            {
                xmldoc.Load(xmlFile);
            }
            catch (FileNotFoundException)
            {
                ShowErrorDialog("File PlugMeterControl.xml is missing.");
            }

            XmlNodeList xmlnode = xmldoc.GetElementsByTagName("CALIBRATION");

            for (i = 0; i < xmlnode.Count; i++)
            {
                String tmp_str;
                for (int j = 0; j < xmlnode[i].ChildNodes.Count; j++)
                {
                    switch (xmlnode[i].ChildNodes[j].Name)
                    {
                        case "Vpp":
						    tmp_str = xmlnode[i].ChildNodes[j].InnerText.ToString();
							if (dutchNumberStyle)
							{
							    tmp_str = tmp_str.Replace(".", ",");
							}
                            CalibrationRef50Data.Vpp.fval = float.Parse(tmp_str);
                            CalibrationRef60Data.Vpp.fval = CalibrationRef50Data.Vpp.fval;
                            break;
                        case "I1pp":
						    tmp_str = xmlnode[i].ChildNodes[j].InnerText.ToString();
							if (dutchNumberStyle)
							{
							    tmp_str = tmp_str.Replace(".", ",");
							}
                            CalibrationRef50Data.I1pp.fval = float.Parse(tmp_str);
                            CalibrationRef60Data.I1pp.fval = CalibrationRef50Data.I1pp.fval;
                            break;
                        case "I2pp":
						    tmp_str = xmlnode[i].ChildNodes[j].InnerText.ToString();
							if (dutchNumberStyle)
							{
							    tmp_str = tmp_str.Replace(".", ",");
							}
                            CalibrationRef50Data.I2pp.fval = float.Parse(tmp_str);
                            CalibrationRef60Data.I2pp.fval = CalibrationRef50Data.I2pp.fval;
                            break;
                        case "DeltaPhi1":
						    tmp_str = xmlnode[i].ChildNodes[j].InnerText.ToString();
							if (dutchNumberStyle)
							{
							    tmp_str = tmp_str.Replace(".", ",");
							}
                            CalibrationRef50Data.DeltaPhi1.fval = float.Parse(tmp_str);
                            CalibrationRef60Data.DeltaPhi1.fval = CalibrationRef50Data.DeltaPhi1.fval;
                            break;
                        case "DeltaPhi2":
						    tmp_str = xmlnode[i].ChildNodes[j].InnerText.ToString();
							if (dutchNumberStyle)
							{
							    tmp_str = tmp_str.Replace(".", ",");
							}
                            CalibrationRef50Data.DeltaPhi2.fval = float.Parse(tmp_str);
                            CalibrationRef60Data.DeltaPhi2.fval = CalibrationRef50Data.DeltaPhi2.fval;
                            break;
                        case "CONFIG":
                            {
                                XmlAttributeCollection xmlattrc = xmlnode[i].ChildNodes[j].Attributes;

                                if ((xmlattrc[0].Name == "Freq") && (xmlattrc[0].Value == "50Hz"))
                                {
                                    for (int k = 0; k < xmlnode[i].ChildNodes[j].ChildNodes.Count; k++)
                                    {
									    tmp_str = xmlnode[i].ChildNodes[j].ChildNodes[k].InnerText.ToString();
							            if (dutchNumberStyle)
							            {
							                tmp_str = tmp_str.Replace(".", ",");
							            }
                                        switch (xmlnode[i].ChildNodes[j].ChildNodes[k].Name)
                                        {
                                            case "Vref":
                                                CalibrationRef50Data.Vref.fval = float.Parse(tmp_str);
                                                break;
                                            case "I1ref":
                                                CalibrationRef50Data.I1ref.fval = float.Parse(tmp_str);
                                                break;
                                            case "I2ref":
                                                CalibrationRef50Data.I2ref.fval = float.Parse(tmp_str);
                                                break;
                                        }
                                    }
                                }
                                else if ((xmlattrc[0].Name == "Freq") && (xmlattrc[0].Value == "60Hz"))
                                {
                                    for (int k = 0; k < xmlnode[i].ChildNodes[j].ChildNodes.Count; k++)
                                    {
									    tmp_str = xmlnode[i].ChildNodes[j].ChildNodes[k].InnerText.ToString();
							            if (dutchNumberStyle)
							            {
							                tmp_str = tmp_str.Replace(".", ",");
							            }
                                        switch (xmlnode[i].ChildNodes[j].ChildNodes[k].Name)
                                        {
                                            case "Vref":
                                                CalibrationRef60Data.Vref.fval = float.Parse(tmp_str);
                                                break;
                                            case "I1ref":
                                                CalibrationRef60Data.I1ref.fval = float.Parse(tmp_str);
                                                break;
                                            case "I2ref":
                                                CalibrationRef60Data.I2ref.fval = float.Parse(tmp_str);
                                                break;
                                        }
                                    }
                                }

                            }
                            break;
                    }
                }
            }
            xmlnode = xmldoc.GetElementsByTagName("SERIAL_PORT");

            for (i = 0; i < xmlnode.Count; i++)
            {
                for (int j = 0; j < xmlnode[i].ChildNodes.Count; j++)
                {
                    switch (xmlnode[i].ChildNodes[j].Name)
                    {
                        case "PortName":
                            FormOpenPort.PortName = xmlnode[i].ChildNodes[j].InnerText;
                            break;
                        case "PortBaudRate":
                            break;
                        case "PortDataBits":
                            break;
                        case "PortParity":
                            break;
                        case "PortStopbits":
                            break;
                        case "PortHandshake":
                            break;
                    }
                }
            }
            xmlnode = xmldoc.GetElementsByTagName("PRICING");
            FormCost.ConsumedPrice = "0";
            FormCost.ProducedPrice = "0";
            for (i = 0; i < xmlnode.Count; i++)
            {
                for (int j = 0; j < xmlnode[i].ChildNodes.Count; j++)
                {
                    switch (xmlnode[i].ChildNodes[j].Name)
                    {
                        case "Consumed":
                            FormCost.ConsumedPrice = xmlnode[i].ChildNodes[j].InnerText;
                            break;
                        case "Produced":
                            FormCost.ProducedPrice = xmlnode[i].ChildNodes[j].InnerText;
                            break;
                    }
                }
            }

            Initialize();

        }


        //Initialize values
        private void Initialize()
        {
            server = "localhost";
            database = "homeenergya";
            uid = "root";
            password = "password";
            string connectionString;
            connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";

            connection = new MySqlConnection(connectionString);
        }


        //open connection to database
        private bool OpenConnection()
        {
            try
            {
                connection.Open();
                return true;
            }
            catch (MySqlException ex)
            {
                //When handling errors, you can your application's response based on the error number.
                //The two most common error numbers when connecting are as follows:
                //0: Cannot connect to server.
                //1045: Invalid user name and/or password.
                switch (ex.Number)
                {
                    case 0:
                        MessageBox.Show("Cannot connect to server.  Contact administrator");
                        break;

                    case 1045:
                        MessageBox.Show("Invalid username/password, please try again");
                        break;
                }
                return false;
            }
        }

        //Close connection
        private bool CloseConnection()
        {
            try
            {
                connection.Close();
                return true;
            }
            catch (MySqlException ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }

        public void log2db(int plugmeter_ID, float voltage, float current, float power, 
            float Q1, float S,float S1, float PF,  float PF1,
            float SN, float N, float THDI, float Tplus, float Tminus, int ontime)
        {
            string query = "insert into energyusage(plugmeter,voltage,current,power, date, time)values(?plugmeter,?voltage,?current,?power, ?date, ?time)";
            // parameters[0] = new MySqlParameter("?name", MySqlDbType.VarChar, 100);

            //open connection
            if (this.OpenConnection() == true)
            {
                //create command and assign the query and connection from the constructor
                MySqlCommand cmd = new MySqlCommand(query, connection);

                MySqlParameter[] parameters = new MySqlParameter[6];


                parameters[0] = new MySqlParameter("?plugmeter", MySqlDbType.Int32);
                parameters[0].Value = plugmeter_ID;

                parameters[1] = new MySqlParameter("?voltage", MySqlDbType.Float);
                parameters[1].Value = voltage;

                parameters[2] = new MySqlParameter("?current", MySqlDbType.Float);
                parameters[2].Value = current;

                parameters[3] = new MySqlParameter("?power", MySqlDbType.Float);
                parameters[3].Value = power;

                parameters[4] = new MySqlParameter("?date", MySqlDbType.Date);
                parameters[4].Value = DateTime.Today.Date;

                parameters[5] = new MySqlParameter("?time", MySqlDbType.Time);
                parameters[5].Value = DateTime.Now.TimeOfDay;

/*
                parameters[4] = new MySqlParameter("?plugmeter", MySqlDbType.Int32);
                parameters[4].Value = plugmeter_ID;

                parameters[5] = new MySqlParameter("?voltage", MySqlDbType.Float);
                parameters[5].Value = voltage;

                parameters[6] = new MySqlParameter("?current", MySqlDbType.Float);
                parameters[6].Value = current;

                parameters[7] = new MySqlParameter("?power", MySqlDbType.Float);
                parameters[7].Value = power;

                parameters[8] = new MySqlParameter("?plugmeter", MySqlDbType.Int32);
                parameters[8].Value = plugmeter_ID;

                parameters[9] = new MySqlParameter("?voltage", MySqlDbType.Float);
                parameters[9].Value = voltage;

                parameters[10] = new MySqlParameter("?current", MySqlDbType.Float);
                parameters[10].Value = current;

                parameters[11] = new MySqlParameter("?power", MySqlDbType.Float);
                parameters[11].Value = power;

                parameters[12] = new MySqlParameter("?plugmeter", MySqlDbType.Int32);
                parameters[12].Value = plugmeter_ID;

                parameters[13] = new MySqlParameter("?voltage", MySqlDbType.Float);
                parameters[13].Value = voltage;

                parameters[14] = new MySqlParameter("?current", MySqlDbType.Float);
                parameters[14].Value = current;

                parameters[15] = new MySqlParameter("?power", MySqlDbType.Float);
                parameters[15].Value = power;

                parameters[16] = new MySqlParameter("?plugmeter", MySqlDbType.Int32);
                parameters[16].Value = plugmeter_ID;

                parameters[17] = new MySqlParameter("?voltage", MySqlDbType.Float);
                parameters[17].Value = voltage;

                parameters[18] = new MySqlParameter("?current", MySqlDbType.Float);
                parameters[18].Value = current;

                parameters[19] = new MySqlParameter("?power", MySqlDbType.Float);
                parameters[19].Value = power;
//*/
                cmd.Parameters.AddRange(parameters);

                //Execute command
                cmd.ExecuteNonQuery();

                //close connection
                this.CloseConnection();
            }
        }

        private void FormMain_Leave(object sender, EventArgs e)
        {
            MenuItemFileExit_Click(sender, e);
        }

        private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            AppExit();
        }

        private void InitPlugmeterArray()
        {
            int i;
            for (i = 0; i<max_plug_meters; i++)
            {
                pmArray[i].uniqueId = 0;
                pmArray[i].plugmeterOffAirCnt = 0;
                pmArray[i].plugmeterOnAir = false;
                pmArray[i].name = "";
                pmArray[i].mainsFrequency = 0;
                pmArray[i].transmitInterval = 3;
                pmArray[i].relayClosed = true;
                pmArray[i].hwVersion = 0;
                pmArray[i].Vpp.ival = 0;
                pmArray[i].I1pp.ival = 0;
                pmArray[i].I2pp.ival = 0;
                pmArray[i].Phi1.ival = 0;
                pmArray[i].Phi2.ival = 0;
                pmArray[i].md.ontime = 0;
                pmArray[i].md.V.ival = 0;
                pmArray[i].md.I.ival = 0;
                pmArray[i].md.P.ival = 0;
                pmArray[i].md.Q1.ival = 0;
                pmArray[i].md.S.ival = 0;
                pmArray[i].md.S1.ival = 0;
                pmArray[i].md.PF.ival = 0;
                pmArray[i].md.PF1.ival = 0;
                pmArray[i].md.SN.ival = 0;
                pmArray[i].md.N.ival = 0;
                pmArray[i].md.THDI.ival = 0;
                pmArray[i].md.Tplus.ival = 0;
                pmArray[i].md.Tminus.ival = 0;
            }
        }

        private void ShowErrorDialog(String ErrorMsg)
        {
            FormErrorMsg.ErrorMsg = ErrorMsg;
            DialogErrorMsg.ShowDialog();
        }

        // *****************************************************************
        //                         Menu methods
        // *****************************************************************

        private System.IO.FileStream loggingfs;

        private void MenuItemFileNew_Click(object sender, EventArgs e)
        {
            if (StatusBarFileName.Enabled)
                loggingfs.Close();
            loggingfs = File.Create("untitled");
            MenuItemFileClose.Enabled = true;
            MenuItemFileSaveAs.Enabled = true;
            StatusBarFileName.Enabled = true;
            DialogOpenFile.FileName = loggingfs.Name;
            StatusBarFileName.Text = "File: " + DialogOpenFile.FileName;
        }

        private void MenuItemFileOpen_Click(object sender, EventArgs e)
        {
            DialogOpenFile.ShowDialog();
        }

        private void DialogOpenFile_FileOk(object sender, CancelEventArgs e)
        {
            if (StatusBarFileName.Enabled)
                loggingfs.Close();
            loggingfs = File.Open(DialogOpenFile.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            MenuItemFileClose.Enabled = true;
            MenuItemFileSaveAs.Enabled = true;
            StatusBarFileName.Enabled = true;
            StatusBarFileName.Text = "File: " + DialogOpenFile.FileName;
        }

        private void MenuItemFileClose_Click(object sender, EventArgs e)
        {
            if (StatusBarFileName.Enabled)
            {
                loggingfs.Close();
                StatusBarFileName.Enabled = false;
                MenuItemFileClose.Enabled = false;
                MenuItemFileSaveAs.Enabled = false;
                DialogOpenFile.FileName = "";
                StatusBarFileName.Text = "File: " + DialogOpenFile.FileName;
            }
        }

        private void MenuItemFileSaveAs_Click(object sender, EventArgs e)
        {
            DialogSaveFile.ShowDialog();
        }

        private void DialogSaveFile_FileOk(object sender, CancelEventArgs e)
        {
            // old name DialogOpenFile.FileName, new name DialogSaveFile.FileName
            loggingfs.Close();
            File.Move(DialogOpenFile.FileName, DialogSaveFile.FileName);
            DialogOpenFile.FileName = DialogSaveFile.FileName;
            loggingfs = File.Open(DialogOpenFile.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            StatusBarFileName.Text = "File: " + DialogOpenFile.FileName;
        }

        private void AddOrChangeNameInXml(int id, string name)
        {
            bool found = false;
            XmlNodeList xmlnode = xmldoc.GetElementsByTagName("PM_NAMES");
            XmlElement pm_tag = (XmlElement)xmlnode.Item(0);

            for (int i = 0; i < pm_tag.ChildNodes.Count && !found; i++)
            {
                XmlAttributeCollection xmlattrc = pm_tag.ChildNodes[i].Attributes;
                for (int j = 0; j < xmlattrc.Count && !found; j += 2)
                {
                    if ((xmlattrc[j].Name == "id") && (xmlattrc[j].Value == id.ToString()))
                    {
                        if ((xmlattrc[j + 1].Name == "name") && (xmlattrc[j + 1].Value != name))
                        {
                            xmlattrc[j + 1].Value = name;
                            xmldoc.Save(xmlFile);
                        }
                        found = true;
                    }
                }
            }
            if (!found)
            {
                xmlnode = xmldoc.GetElementsByTagName("PM_NAMES");
                pm_tag = (XmlElement)xmlnode.Item(0);
                XmlElement pm = xmldoc.CreateElement("PM");
                XmlAttribute pm_id = xmldoc.CreateAttribute("id");
                pm_id.Value = id.ToString();

                pm.SetAttributeNode(pm_id);
                XmlAttribute pm_name = xmldoc.CreateAttribute("name");
                pm_name.Value = name;
                pm.SetAttributeNode(pm_name);
                pm_tag.AppendChild(pm);

                xmldoc.Save(xmlFile);
            }
        }

        private string GetNameFromXml(int id)
        {
            bool found = false;
            string resultStr = "";

            XmlNodeList xmlnode = xmldoc.GetElementsByTagName("PM_NAMES");
            XmlElement pm_tag = (XmlElement)xmlnode.Item(0);

            for (int i = 0; i < pm_tag.ChildNodes.Count && !found; i++)
            {
                XmlAttributeCollection xmlattrc = pm_tag.ChildNodes[i].Attributes;
                for (int j = 0; j < xmlattrc.Count && !found; j += 2)
                {
                    if ((xmlattrc[j].Name == "id") && (xmlattrc[j].Value == id.ToString()))
                    {
                        resultStr = xmlattrc[j + 1].Value;
                        found = true;
                    }
                }
            }
            return resultStr;
        }

        private void CloseComPort()
        {
            DongleCommand("stop");
            Thread.Sleep(250);
            firstSerialThreadContinue = false;
            firstSerialPortReadThread.Join(500);
            firstSerialPortReadThread.Abort();
            firstSerialPort.Close();
        }

        private void AppExit()
        {
            if (firstSerialPort.IsOpen)
            {
                CloseComPort();
            }
            if (StatusBarFileName.Enabled)
            {
                loggingfs.Close();
                StatusBarFileName.Enabled = false;
            }
        }

        private void MenuItemFileExit_Click(object sender, EventArgs e)
        {
            AppExit();
            Close();
        }

        private void MenuItemViewStatusBar_Click(object sender, EventArgs e)
        {
            MenuItemViewStatusBar.Checked = !MenuItemViewStatusBar.Checked;
            StripStatusBar.Visible = !StripStatusBar.Visible;
        }

        private void MenuItemSetupOpenComPort_Click(object sender, EventArgs e)
        {
            DialogResult result = DialogOpenPort.ShowDialog();
            if (result == DialogResult.OK)
            {
                firstSerialPortReadThread = new Thread(new ThreadStart(this.FirstSerialReadThreadProcSafe));
                firstSerialPort.PortName = FormOpenPort.PortName;
                firstSerialPort.BaudRate = int.Parse(FormOpenPort.PortBaudRate);
                firstSerialPort.DataBits = int.Parse(FormOpenPort.PortDataBits);
                switch (FormOpenPort.PortParity)
                {
                    case "Even": firstSerialPort.Parity = Parity.Even; break;
                    case "Mark": firstSerialPort.Parity = Parity.Mark; break;
                    case "None": firstSerialPort.Parity = Parity.None; break;
                    case "Odd": firstSerialPort.Parity = Parity.Odd; break;
                    case "Space": firstSerialPort.Parity = Parity.Space; break;
                }
                switch (FormOpenPort.PortStopbits)
                {
                    case "None": firstSerialPort.StopBits = StopBits.None; break;
                    case "One": firstSerialPort.StopBits = StopBits.One; break;
                    case "OnePointFive": firstSerialPort.StopBits = StopBits.OnePointFive; break;
                    case "Two": firstSerialPort.StopBits = StopBits.Two; break;
                }
                switch (FormOpenPort.PortHandshake)
                {
                    case "None": firstSerialPort.Handshake = Handshake.None; break;
                    case "RequestToSend": firstSerialPort.Handshake = Handshake.RequestToSend; break;
                    case "RequestToSendXOnXOff": firstSerialPort.Handshake = Handshake.RequestToSendXOnXOff; break;
                    case "XOnXOff": firstSerialPort.Handshake = Handshake.XOnXOff; break;
                }
                firstSerialPort.ReadTimeout = 500;
                firstSerialPort.WriteTimeout = 500;
                try
                {
                    firstSerialPortOpenTime = DateTime.UtcNow;
                    firstSerialPort.Open();
                    firstSerialPortReadThread.Start();
                    StopSniffing();
                    DongleCommand("rx m");
                    DongleCommand("info");
                    DongleCommand("uptime");
                    DongleCommand("start");
                    EnableGuiElements(true);
                    ResetChartPowerUsage();
                    RefreshPlugMeterView();
                    RefreshConfigurationValues(false);
              //      RefreshCalibrationValues(false);

                    XmlNodeList xmlnode = xmldoc.GetElementsByTagName("SERIAL_PORT");
                    for (int i = 0; i < xmlnode.Count; i++)
                    {
                        for (int j = 0; j < xmlnode[i].ChildNodes.Count; j++)
                        {
                            if ((xmlnode[i].ChildNodes[j].Name == "PortName") &&
                                (xmlnode[i].ChildNodes[j].InnerText != FormOpenPort.PortName))
                            {
                                xmlnode[i].ChildNodes[j].InnerText = FormOpenPort.PortName;
                                xmldoc.Save(xmlFile);
                                break;
                            }
                        }
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    ShowErrorDialog("Communication port couldn't be opened, maybe it's in use already.");
                }
            }
        }

        private void EnableGuiElements(bool portOpen)
        {
            MenuItemSetupOpenComPort.Enabled = !portOpen;
            MenuItemSetupCloseComPort.Enabled = portOpen;
            timerTestOffAir.Enabled = portOpen;
            groupBoxPlugmeter.Enabled = portOpen;
            groupBoxRelay.Enabled = portOpen;
            groupBoxTransmitInterval.Enabled = portOpen;
            groupBoxReadings.Enabled = portOpen;
         //   textBoxCommand.Enabled = portOpen;
         //   buttonHelp.Enabled = portOpen;
         //   groupBoxCVPlugmeter.Enabled = portOpen;
         //   groupBoxCVConfig.Enabled = portOpen;
         //   groupBoxRelayTest.Enabled = portOpen;
        //    groupBoxCalPlugmeter.Enabled = portOpen;
        //    textBoxCName.Enabled = portOpen;
        //    groupBoxCalConfigV.Enabled = portOpen;
        //    groupBoxCalMeasurmentV.Enabled = portOpen;
        //    StartCalibrationButton.Enabled = portOpen;
            groupBoxChipRate.Enabled = (portOpen && sniffingStarted);
            buttonSnifferStart.Enabled = portOpen;
            buttonSnifferClean.Enabled = portOpen;
            StatusBarPortStatus.Text = "Port: ";
            if (portOpen)
                StatusBarPortStatus.Text += FormOpenPort.PortName + " open";
            else
                StatusBarPortStatus.Text += "closed";
            dongleConnected = portOpen;
            UpdateConnectionStatus(portOpen);
        }

        private void MenuItemSetupCloseComPort_Click(object sender, EventArgs e)
        {
            int i;
            CloseComPort();
            EnableGuiElements(false);
            InitPlugmeterArray();
            for (i = numberOfPlugmeters; i >= 0; i--)
            {
                if (i <= 8)
                {
                    dataGridViewAll.Rows[i].Cells[1].Value = "";
                    dataGridViewAll.Rows[i].Cells[2].Value = "No";
                    dataGridViewAll.Rows[i].Cells[3].Value = "";
                    dataGridViewAll.Rows[i].Cells[4].Value = "";
                    dataGridViewAll.Rows[i].Cells[5].Value = "";
                    dataGridViewAll.Rows[i].Cells[6].Value = "";
                    dataGridViewAll.Rows[i].Cells[7].Value = "";
                    dataGridViewAll.Rows[i].Cells[8].Value = "";
                    dataGridViewAll.Rows[i].Cells[9].Value = "";
                    dataGridViewAll.Rows[i].Cells[10].Value = "";
                    dataGridViewAll.Rows[i].Cells[11].Value = "";
                    dataGridViewAll.Rows[i].Cells[12].Value = "";
                    dataGridViewAll.Rows[i].Cells[13].Value = "";
                    dataGridViewAll.Rows[i].Cells[14].Value = "";
                    dataGridViewAll.Rows[i].Cells[15].Value = "";
                    dataGridViewAll.Rows[i].Cells[16].Value = "";
                    dataGridViewAll.Rows[i].Cells[17].Value = "";
                }
                else
                    dataGridViewAll.Rows.RemoveAt(i);
            }
            numberOfPlugmeters = 8;
            dataGridViewAll.Rows[numberOfPlugmeters].Cells[0].Value = "";
            dataGridViewAll.Rows[numberOfPlugmeters].Cells[1].Value = "Total";
            dataGridViewAll.Rows[numberOfPlugmeters].Cells[2].Value = "0";
            radioButtonPM00.Checked = true;
            radioButtonPM1.Checked = true;
            RefreshPlugMeterView();
         //   radioButtonCVPM00.Checked = true;
        //    radioButtonCVPM1.Checked = true;
     //       RefreshConfigurationValues(false);
       //     RefreshCalibrationValues(false);
        }

        private void MenuItemHelpAbout_Click(object sender, EventArgs e)
        {
            DialogAbout.ShowDialog();
        }

        // *****************************************************************
        //                         Serial Port methods
        // *****************************************************************

        private void WriteFirstSerial(String msg)
        {
            try
            {
                if (CommunicateWithOldRfDongleSW)
                {
                    // The old dongle SW tests on the \n character in the command string
                    firstSerialPort.WriteLine(msg);
                }
                else
                {
                    // The new dongle SW tests on the \r character in the command string
                    // This is changed because then Minicom on Linux systems can also be supported by the dongle
                    firstSerialPort.WriteLine(msg + "\r");
                }
            }
            catch (TimeoutException) { }
        }

        private void FirstSerialReadThreadProcSafe()
        {
            String message = "";
            char[] new_char = { ' ' };
            bool EndOfLine = false;

            firstSerialThreadContinue = true;
            while (firstSerialThreadContinue)
            {
                message = "";
                EndOfLine = false;
                while (!EndOfLine)
                {
                    try
                    {
                        firstSerialPort.Read(new_char, 0, 1);
                        if (new_char.ElementAt(0) == '>' && (message.Length == 0))
                            HandleFirstSerialReceivedText(">");
                        else if (new_char.ElementAt(0) == '$' && (message.Length == 0))
                            HandleFirstSerialReceivedText("$");
                        else if (new_char.ElementAt(0) == '.' && (message.Length == 0))
                            HandleFirstSerialReceivedText(".");
                        else if (new_char.ElementAt(0) == '\n')
                            EndOfLine = true;
                        else if (new_char.ElementAt(0) != '\r')
                            message += new String(new_char);
                    }
                    catch (TimeoutException) { }
                }
                HandleFirstSerialReceivedText(message);
            }
        }

        // This delegate enables asynchronous calls for setting the text property on a TextBox control.
        delegate void AddTextCallback(String msg);

        // This method demonstrates a pattern for making thread-safe
        // calls on a Windows Forms control. 
        //
        // If the calling thread is different from the thread that
        // created the textBox control, this method creates a
        // AddTextCallback and calls itself asynchronously using the
        // Invoke method.
        //
        // If the calling thread is the same as the thread that created
        // the textBox control, the Text property is set directly. 
        private void HandleFirstSerialReceivedText(String msg)
        {
       //     if (this.textBoxControl.InvokeRequired)
       //     {
       //         AddTextCallback d = new AddTextCallback(HandleFirstSerialReceivedText);
       //         this.Invoke(d, new object[] { msg });
       //     }
       //     else
            {
                ParseMbusModeMsg(msg);
            }
        }

        // *****************************************************************
        //                  Parse and handle incomming msgs
        // *****************************************************************

        // Example:
        //    The following msg is received from the NXP OL2381 dongle.
        //
        //        MBUS:00000186,036F,64,00,A0,11,0C,44,10,3B,0A,08,22,EC,03,02,09,57,A0,72,4F,B5,56
        //
        //    It is a human readable msg to make debugging easy.
        //    The string starts with a header which is generated by the dongle when receiving the mbus msg.
        //    The following indicates how the msg is build up,
        //
        //    dongle generated part -> MBUS:00000186,036F,64,00,A0,11,
        //    actual mbus msg       ->                                0C,44,10,3B,0A,08,22,EC,03,02,09,57,A0,72,4F,B5,56
        //
        //    The dongle genarated part contains <MBUS>:<seconds count>,<milli seconds count>,<chiprate>,<status>,<rssi_level>,<length>
        //    The Mbus msg is build up of blocks. The first block of 12 bytes is the Mbus header, followed with 1 or more data blocks.
        //    The Mbus data blocks carry max 16 bytes, followed by a CRC.
        //    Here is the Mbus header definition:
        //       L-field             (1 byte)   - Specifies the length of the Mbus msg minus the CRC bytes and this L-field
        //       C-field             (1 byte)   - Type of msg
        //       Manufacturer ID     (2 bytes)
        //       unique Device ID    (4 bytes)
        //       Device version nr   (1 byte)
        //       Device type         (1 byte)
        //       header CRC          (2 bytes)

        private int rf_msg_counter = 0;

        private void ParseMbusModeMsg(String msg)
        {
            int cnt = CountColonsInString(msg);
            String[] parts = msg.Split(',');
            if (msg.StartsWith("MBUS:") && (cnt > 5))
            {
                rf_msg_counter += 1;
                parts[0] = parts[0].Replace("MBUS:", "");
                dongleUptimeSeconds = int.Parse(parts[0], System.Globalization.NumberStyles.HexNumber);
                String timeofday = Secs2timeofday(dongleUptimeSeconds, false);
                short rf_mseconds = short.Parse(parts[1], System.Globalization.NumberStyles.HexNumber);
                timeofday += ":" + rf_mseconds.ToString();
                byte chiprate = byte.Parse(parts[2], System.Globalization.NumberStyles.HexNumber);
                byte status = byte.Parse(parts[3], System.Globalization.NumberStyles.HexNumber);
                byte rssi_level = byte.Parse(parts[4], System.Globalization.NumberStyles.HexNumber);
                byte length = byte.Parse(parts[5], System.Globalization.NumberStyles.HexNumber);
                String rf_man_id = "";
                String rf_sender = "";
                String rf_dev_version = "";
                String rf_dev_type = "";
                int man_id = 0;
                int dev_type = 0;
                int dev_version = 0;
                // status 0 means that the CRC of the mbus msg header (parts[16] and parts[17]) is OK
                if ((status == 0) && (length >= 12))
                {
                    // process data from the mbus msg header
                    man_id = int.Parse(parts[9] + parts[8], System.Globalization.NumberStyles.HexNumber);
                    char letter1 = (char)(((man_id >> 10) & 31) + 64);
                    char letter2 = (char)(((man_id >> 5) & 31) + 64);
                    char letter3 = (char)(((man_id >> 0) & 31) + 64);
                    rf_man_id = letter1.ToString() + letter2.ToString() + letter3.ToString();
                    rf_sender = parts[13] + parts[12] + parts[11] + parts[10];
                    dev_version = int.Parse(parts[14], System.Globalization.NumberStyles.HexNumber);
                    rf_dev_version = dev_version.ToString();
                    dev_type = int.Parse(parts[15], System.Globalization.NumberStyles.HexNumber);
                    rf_dev_type = dev_type.ToString();
                }
                // only at 100Kchips we receive plugmeter msgs, and dev_type should be Electricity (2)
                if (radioButton100K.Checked && (dev_type == 2) && (length > (12 + 2)))
                {
                    int pm_id = int.Parse(rf_sender, System.Globalization.NumberStyles.HexNumber);
                    int plugmeter = CheckAndAddIfNewPlugmeter(pm_id);
                    if (plugmeter > 0)
                    {
                        pmArray[plugmeter - 1].hwVersion = dev_version;
                        // length of second block is max 16 bytes
                        int check_len = 16;
                        // check if second block is smaller then 16 bytes
                        if (length < 30)
                        {
                            check_len = length - (12 + 2); // mbus msg header is 12 bytes, crc is last 2 bytes
                        }
                        // Check the CRC of the second block of the mbus msg, CRC in parts[x] and parts[x+1] (x depends on msg length)
                        int i;
                        for (i=0; i < check_len; i++)
                        {
                            mbusDataBlock[i] = byte.Parse(parts[18 + i], System.Globalization.NumberStyles.HexNumber);
                        }
                        short msg_crc = short.Parse(parts[18 + i] + parts[18 + i + 1], System.Globalization.NumberStyles.HexNumber);
                        bool crc1_ok = CheckMbusCRC(mbusDataBlock, check_len, msg_crc);
                        if (crc1_ok)
                        {
                            // parts[18] contains 0xA0 (Manufacturer specific msg)
                            if ((length == 76) || (length == 80))
                            {
                                // the Plugmeter measuring data msg doesn't carry a msg id, so we used the msg length to recognise it.
                                pmArray[plugmeter - 1].rssi = rssi_level;
                                // check CRC in parts[52] and parts[53]
                                check_len = 16;
                                for (i = 0; i < check_len; i++)
                                {
                                    mbusDataBlock[i] = byte.Parse(parts[36 + i], System.Globalization.NumberStyles.HexNumber);
                                }
                                msg_crc = short.Parse(parts[36 + i] + parts[36 + i + 1], System.Globalization.NumberStyles.HexNumber);
                                bool crc2_ok = CheckMbusCRC(mbusDataBlock, check_len, msg_crc);
                                // check CRC in parts[70] and parts[71]
                                check_len = 16;
                                for (i = 0; i < check_len; i++)
                                {
                                    mbusDataBlock[i] = byte.Parse(parts[54 + i], System.Globalization.NumberStyles.HexNumber);
                                }
                                msg_crc = short.Parse(parts[54 + i] + parts[54 + i + 1], System.Globalization.NumberStyles.HexNumber);
                                bool crc3_ok = CheckMbusCRC(mbusDataBlock, check_len, msg_crc);
                                if (length == 76)
                                    check_len = 8;    // check CRC in parts[80] and parts[81]
                                else
                                    check_len = 12;    // check CRC in parts[84] and parts[85]
                                for (i = 0; i < check_len; i++)
                                {
                                    mbusDataBlock[i] = byte.Parse(parts[72 + i], System.Globalization.NumberStyles.HexNumber);
                                }
                                msg_crc = short.Parse(parts[72 + i] + parts[72 + i + 1], System.Globalization.NumberStyles.HexNumber);
                                bool crc4_ok = CheckMbusCRC(mbusDataBlock, check_len, msg_crc);
                                if (crc2_ok && crc3_ok && crc4_ok)
                                {
                                    pmArray[plugmeter - 1].md.ontime = int.Parse(parts[21] + parts[20] + parts[19], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.V.ival = int.Parse(parts[25] + parts[24] + parts[23] + parts[22], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.I.ival = int.Parse(parts[29] + parts[28] + parts[27] + parts[26], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.P.ival = int.Parse(parts[33] + parts[32] + parts[31] + parts[30], System.Globalization.NumberStyles.HexNumber);
                                    // CRC in parts[34] and parts[35]
                                    pmArray[plugmeter - 1].md.Q1.ival = int.Parse(parts[39] + parts[38] + parts[37] + parts[36], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.S.ival  = int.Parse(parts[43] + parts[42] + parts[41] + parts[40], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.S1.ival = int.Parse(parts[47] + parts[46] + parts[45] + parts[44], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.PF.ival = int.Parse(parts[51] + parts[50] + parts[49] + parts[48], System.Globalization.NumberStyles.HexNumber);
                                    // CRC in part[52] and parts[53]
                                    pmArray[plugmeter - 1].md.PF1.ival  = int.Parse(parts[57] + parts[56] + parts[55] + parts[54], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.SN.ival   = int.Parse(parts[61] + parts[60] + parts[59] + parts[58], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.N.ival    = int.Parse(parts[65] + parts[64] + parts[63] + parts[62], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.THDI.ival = int.Parse(parts[69] + parts[68] + parts[67] + parts[66], System.Globalization.NumberStyles.HexNumber);
                                    // CRC in parts[70] and parts[71]
                                    pmArray[plugmeter - 1].md.Tplus.ival  = int.Parse(parts[75] + parts[74] + parts[73] + parts[72], System.Globalization.NumberStyles.HexNumber);
                                    pmArray[plugmeter - 1].md.Tminus.ival = int.Parse(parts[79] + parts[78] + parts[77] + parts[76], System.Globalization.NumberStyles.HexNumber);
                                    if (length == 80)
                                    {
                                        pmArray[plugmeter - 1].mainsFrequency = int.Parse(parts[80], System.Globalization.NumberStyles.HexNumber);
                                        if (int.Parse(parts[81], System.Globalization.NumberStyles.HexNumber) == (int)'C')
                                            pmArray[plugmeter - 1].relayClosed = true;
                                        else if (int.Parse(parts[81], System.Globalization.NumberStyles.HexNumber) == (int)'O')
                                            pmArray[plugmeter - 1].relayClosed = false;
                                        pmArray[plugmeter - 1].transmitInterval = int.Parse(parts[83] + parts[82], System.Globalization.NumberStyles.HexNumber);
                                    }
                                    log2db(plugmeter, pmArray[plugmeter - 1].md.V.fval, pmArray[plugmeter - 1].md.I.fval, pmArray[plugmeter - 1].md.P.fval, pmArray[plugmeter - 1].md.Q1.fval,
                                        pmArray[plugmeter - 1].md.S.fval, pmArray[plugmeter - 1].md.S1.fval, pmArray[plugmeter - 1].md.PF.fval, pmArray[plugmeter - 1].md.PF1.fval,
                                        pmArray[plugmeter - 1].md.SN.fval, pmArray[plugmeter - 1].md.N.fval, pmArray[plugmeter - 1].md.THDI.fval, pmArray[plugmeter - 1].md.Tplus.fval,
                                        pmArray[plugmeter - 1].md.Tminus.fval,pmArray[plugmeter - 1].md.ontime);
                                    HandleMeasuredData(plugmeter);
                                }
                            }
                            else
                            {
                                int cmd = int.Parse(parts[19], System.Globalization.NumberStyles.HexNumber);
                                if (cmd == (int)'a')
                                {
                                    int state = int.Parse(parts[20], System.Globalization.NumberStyles.HexNumber);
                                    DialogCalibration.SetCalibrationState(state);
                                }
                                else if (cmd == (int)'r')
                                {
                                    if (int.Parse(parts[20], System.Globalization.NumberStyles.HexNumber) == (int)'C')
                                        pmArray[plugmeter - 1].relayClosed = true;
                                    else if (int.Parse(parts[20], System.Globalization.NumberStyles.HexNumber) == (int)'O')
                                        pmArray[plugmeter - 1].relayClosed = false;
                                    // CRC in parts[21] and parts[22]
                                    HandleRelayResponse(plugmeter);
                                }
                                else if (cmd == (int)'t')
                                {
                                    pmArray[plugmeter - 1].transmitInterval = int.Parse(parts[21] + parts[20], System.Globalization.NumberStyles.HexNumber);
                                    // CRC in parts[22] and parts[23]
                                    HandleTxtimeResponse(plugmeter);
                                }
                                else if (cmd == (int)'c')
                                {
                                    bool crc2_ok = false;
                                    if (length == 40)
                                    {
                                        // Check the CRC of the third block of the mbus msg in parts[44] and parts[45]
                                        check_len = 8;
                                        for (i = 0; i < check_len; i++)
                                        {
                                            mbusDataBlock[i] = byte.Parse(parts[36 + i], System.Globalization.NumberStyles.HexNumber);
                                        }
                                        msg_crc = short.Parse(parts[36 + i] + parts[36 + i + 1], System.Globalization.NumberStyles.HexNumber);
                                        crc2_ok = CheckMbusCRC(mbusDataBlock, check_len, msg_crc);
                                    }
                                    if (crc2_ok)
                                    {
                                        pmArray[plugmeter - 1].mainsFrequency = int.Parse(parts[20], System.Globalization.NumberStyles.HexNumber);
                                        // parts[21] is reserved for future use
                                        pmArray[plugmeter - 1].Vpp.ival  = int.Parse(parts[25] + parts[24] + parts[23] + parts[22], System.Globalization.NumberStyles.HexNumber);
                                        pmArray[plugmeter - 1].I1pp.ival = int.Parse(parts[29] + parts[28] + parts[27] + parts[26], System.Globalization.NumberStyles.HexNumber);
                                        pmArray[plugmeter - 1].I2pp.ival = int.Parse(parts[33] + parts[32] + parts[31] + parts[30], System.Globalization.NumberStyles.HexNumber);
                                        // CRC in parts[34] and parts[35]
                                        pmArray[plugmeter - 1].Phi1.ival = int.Parse(parts[39] + parts[38] + parts[37] + parts[36], System.Globalization.NumberStyles.HexNumber);
                                        pmArray[plugmeter - 1].Phi2.ival = int.Parse(parts[43] + parts[42] + parts[41] + parts[40], System.Globalization.NumberStyles.HexNumber);
                                        // CRC in parts[44] and parts[45]
                                        HandleConfigResponse(plugmeter);
                                    }
                                }
                                else if (cmd == (int)'s')
                                {
                                    // handle store ack
                                    // Todo: ??
                                }
                            }
                        }
                    }
                }
                if (sniffingStarted)
                {
                    String rf_status = "";
                    switch (status)
                    {
                        case 0x00 /*   0 */: rf_status = "OK"; break;
                        case 0xFE /*  -2 */: rf_status = "READ DATA TIMEOUT"; break;
                        case 0xEC /* -20 */: rf_status = "BAD CRC IN MSG HEADER"; break;
                        case 0xEB /* -21 */: rf_status = "READ DATA ERR LEN"; break;
                        default:  rf_status = ""; break;
                    }
                    String rf_data = "";
                    int i;
                    for (i = 0; i < length; i++)
                    {
                        if (i != 0)
                            rf_data += ",";
                        rf_data += parts[6 + i];
                    }
                    Color msgColor = Color.Black;
                    if (chiprate == 32)
                        msgColor = Color.Blue;
                    if (status != 0)
                        msgColor = Color.Red;
                    SniffingAddText("msg=" + rf_msg_counter.ToString() + ", time=" + timeofday + ", rate=" + chiprate.ToString() +
                                    ", stat=" + rf_status + ", rssi=" + rssi_level.ToString() + ", len=" + length.ToString() + ", man=" + rf_man_id +
                                    ", snd=" + rf_sender + ", ver=" + rf_dev_version + ", type=" + rf_dev_type + ", data=" + rf_data,
                                    msgColor);
                }
                else
                {
                    WriteLineToLogFile(msg);
                    LoggingAddText(msg);
                }
            }
            else
                ControlAddText(msg);
        }

        private void HandleRelayResponse(int plugmeter)
        {
            SetOnAirStatus(plugmeter);
            if (plugmeter == SelectedPlugmeter())
            {
                UpdatePMViewRelayStatus(plugmeter);
                UpdatePMViewOnAirStatus(plugmeter);
            }
        }

        private void HandleTxtimeResponse(int plugmeter)
        {
            SetOnAirStatus(plugmeter);
            if (plugmeter == SelectedPlugmeter())
            {
                textBoxTransmitInterval.Text = pmArray[plugmeter - 1].transmitInterval.ToString();
            }
        }

        private void HandleConfigResponse(int plugmeter)
        {
            SetOnAirStatus(plugmeter);
            if (plugmeter == SelectedPlugmeter())
            {
                textBoxFreq.Text = pmArray[plugmeter - 1].mainsFrequency.ToString();
            }
            if (plugmeter == SelectedConfigPlugmeter())
            {
          //      textBoxVpp.Text = pmArray[plugmeter - 1].Vpp.fval.ToString("F3");
          //      textBoxI1pp.Text = pmArray[plugmeter - 1].I1pp.fval.ToString("F3");
           //     textBoxI2pp.Text = pmArray[plugmeter - 1].I2pp.fval.ToString("F3");
         //       textBoxPhi1.Text = pmArray[plugmeter - 1].Phi1.fval.ToString("F3");
          //      textBoxPhi2.Text = pmArray[plugmeter - 1].Phi2.fval.ToString("F3");
            }
            /*
            if (plugmeter == SelectedCalibrationPlugmeter())
            {
                textBoxCVpp.Text = pmArray[plugmeter - 1].Vpp.fval.ToString("F3");
                textBoxCI1pp.Text = pmArray[plugmeter - 1].I1pp.fval.ToString("F3");
                textBoxCI2pp.Text = pmArray[plugmeter - 1].I2pp.fval.ToString("F3");
                textBoxCDP1.Text = pmArray[plugmeter - 1].Phi1.fval.ToString("F6");
                textBoxCDP2.Text = pmArray[plugmeter - 1].Phi2.fval.ToString("F6");
            }
             * //*/
        }

        private void HandleMeasuredData(int plugmeter)
        {
            SetOnAirStatus(plugmeter);
            String ontime = Secs2timeofday(pmArray[plugmeter - 1].md.ontime, true);
            if (firstSerialPort.IsOpen)
            {
                if (plugmeter == SelectedPlugmeter())
                {
                    textBoxPMname.Text = pmArray[plugmeter - 1].name;
                    textBoxVoltage.Text = pmArray[plugmeter - 1].md.V.fval.ToString("F3");
                    textBoxCurrent.Text = pmArray[plugmeter - 1].md.I.fval.ToString("F3");
                    textBoxP.Text = pmArray[plugmeter - 1].md.P.fval.ToString("F3");
                    textBoxQ1.Text = pmArray[plugmeter - 1].md.Q1.fval.ToString("F3");
                    textBoxS.Text = pmArray[plugmeter - 1].md.S.fval.ToString("F3");
                    textBoxS1.Text = pmArray[plugmeter - 1].md.S1.fval.ToString("F3");
                    textBoxPF.Text = pmArray[plugmeter - 1].md.PF.fval.ToString("F2");
                    textBoxPF1.Text = pmArray[plugmeter - 1].md.PF1.fval.ToString("F2");
                    textBoxSN.Text = pmArray[plugmeter - 1].md.SN.fval.ToString("F3");
                    textBoxN.Text = pmArray[plugmeter - 1].md.N.fval.ToString("F3");
                    textBoxTHDI.Text = pmArray[plugmeter - 1].md.THDI.fval.ToString("F3");
                    textBoxTplus.Text = pmArray[plugmeter - 1].md.Tplus.fval.ToString("F3");
                    textBoxTminus.Text = pmArray[plugmeter - 1].md.Tminus.fval.ToString("F3");
                    textBoxOnTime.Text = ontime;
// JvdG: Next line commented out because it makes it unpossible for the user to edit the field 
//                    textBoxTransmitInterval.Text = pmArray[plugmeter - 1].transmitInterval.ToString();
                    textBoxFreq.Text = pmArray[plugmeter - 1].mainsFrequency.ToString();
                    UpdatePMViewRelayStatus(plugmeter);
                    UpdatePMViewOnAirStatus(plugmeter);
                }
                UpdateChartPowerUsage(plugmeter, pmArray[plugmeter - 1].md.P.fval);
                try
                {
                    dataGridViewAll.Rows[plugmeter - 1].Cells[1].Value = pmArray[plugmeter - 1].name;
                    dataGridViewAll.Rows[plugmeter - 1].Cells[3].Value = pmArray[plugmeter - 1].md.V.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[4].Value = pmArray[plugmeter - 1].md.I.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[5].Value = pmArray[plugmeter - 1].md.P.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[6].Value = pmArray[plugmeter - 1].md.Tplus.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[7].Value = (pmArray[plugmeter - 1].md.Tplus.fval * float.Parse(FormCost.ConsumedPrice) * (float)0.01).ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[8].Value = pmArray[plugmeter - 1].md.Tminus.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[9].Value = (pmArray[plugmeter - 1].md.Tminus.fval * float.Parse(FormCost.ProducedPrice) * (float)0.01).ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[11].Value = pmArray[plugmeter - 1].md.N.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[12].Value = pmArray[plugmeter - 1].md.S.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[13].Value = pmArray[plugmeter - 1].md.PF.fval.ToString("F2");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[14].Value = pmArray[plugmeter - 1].md.Q1.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[15].Value = pmArray[plugmeter - 1].md.S1.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[16].Value = pmArray[plugmeter - 1].md.PF1.fval.ToString("F2");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[17].Value = pmArray[plugmeter - 1].md.SN.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[18].Value = pmArray[plugmeter - 1].md.THDI.fval.ToString("F3");
                    dataGridViewAll.Rows[plugmeter - 1].Cells[19].Value = pmArray[plugmeter - 1].rssi.ToString();
                    dataGridViewAll.Rows[plugmeter - 1].Cells[10].Value = ontime;
                    UpdateTotals();
                }
                catch (ArgumentOutOfRangeException) { }
                /*
                if (plugmeter == SelectedCalibrationPlugmeter())
                {
                    textBoxCV.Text = pmArray[plugmeter - 1].md.V.fval.ToString("F3");
                    textBoxCI.Text = pmArray[plugmeter - 1].md.I.fval.ToString("F3");
                    textBoxCP.Text = pmArray[plugmeter - 1].md.P.fval.ToString("F3");
                    textBoxCQ1.Text = pmArray[plugmeter - 1].md.Q1.fval.ToString("F3");
                }
                 * //*/
            }
        }

        // *****************************************************************
        //                     Status bar methods
        // *****************************************************************

        private void UpdateConnectionStatus(bool portOpen)
        {
            StatusBarConnectionStatus.Text = "RF dongle: ";
            StatusBarConnectionStatus.Enabled = portOpen;
            if (portOpen)
            {
                if (dongleConnected)
                {
                    StatusBarConnectionStatus.Text += " connected";
                    StatusBarConnectionStatus.BackColor = Color.FromArgb(151, 146, 0);
                }
                else
                {
                    StatusBarConnectionStatus.Text += " disconnected";
                    StatusBarConnectionStatus.BackColor = Color.FromArgb(227, 0, 74);
                }
            }
            else
                StatusBarConnectionStatus.BackColor = Color.White;
        }

        // *****************************************************************
        //                     Plugmeter commands
        // *****************************************************************

        private void PlugmeterCommandForced(String command, int plugmeter, String sub_command)
        {
            if (firstSerialPort.IsOpen && (!sniffingStarted) && (pmArray[plugmeter - 1].hwVersion > 2))
            {
                String cmd = command + " " + pmArray[plugmeter - 1].uniqueId.ToString() + " " + sub_command;
                ControlAddText(cmd);
                WriteFirstSerial(cmd);
            }
        }

        private void PlugmeterCommand(String command, int plugmeter, String sub_command)
        {
            if (firstSerialPort.IsOpen && (!sniffingStarted) &&
                (pmArray[plugmeter - 1].plugmeterOnAir) &&
                (pmArray[plugmeter - 1].hwVersion > 2))
            {
                String cmd = command + " " + pmArray[plugmeter - 1].uniqueId.ToString() + " " + sub_command;
                ControlAddText(cmd);
                WriteFirstSerial(cmd);
            }
        }

        private void PlugmeterCommand(String command, int plugmeter, String sub_command, String parm1)
        {
            if (firstSerialPort.IsOpen && (!sniffingStarted) &&
                (pmArray[plugmeter - 1].plugmeterOnAir) &&
                (pmArray[plugmeter - 1].hwVersion > 2))
            {
                String cmd = command + " " + pmArray[plugmeter - 1].uniqueId.ToString() + " " + sub_command + " " + parm1;
                ControlAddText(cmd);
                WriteFirstSerial(cmd);
            }
        }

        private void PlugmeterCommand(String command, int plugmeter, String sub_command, String parm1, String parm2, String parm3, String parm4, String parm5)
        {
            if (firstSerialPort.IsOpen && (!sniffingStarted) &&
                (pmArray[plugmeter - 1].plugmeterOnAir) &&
                (pmArray[plugmeter - 1].hwVersion > 2))
            {
                String cmd = command + " " + pmArray[plugmeter - 1].uniqueId.ToString() + " " + sub_command + " " +
                             parm1 + " " + parm2 + " " + parm3 + " " + parm4 + " " + parm5;
                ControlAddText(cmd);
                WriteFirstSerial(cmd);
            }
        }

        private void PlugmeterCommand(String command, int plugmeter, String sub_command, String parm1, String parm2, String parm3, String parm4, String parm5, String parm6)
        {
            if (firstSerialPort.IsOpen && (!sniffingStarted) &&
                (pmArray[plugmeter - 1].plugmeterOnAir) &&
                (pmArray[plugmeter - 1].hwVersion > 2))
            {
                String cmd = command + " " + pmArray[plugmeter - 1].uniqueId.ToString() + " " + sub_command + " " +
                             parm1 + " " + parm2 + " " + parm3 + " " + parm4 + " " + parm5 + " " + parm6;
                ControlAddText(cmd);
                WriteFirstSerial(cmd);
            }
        }

        // *****************************************************************
        //                      Dongle commands
        // *****************************************************************

        private void DongleCommand(String command)
        {
            if (firstSerialPort.IsOpen)
            {
                ControlAddText(command);
                WriteFirstSerial(command);
            }
        }

        // *****************************************************************
        //                      Helper methods
        // *****************************************************************

        private String Secs2timeofday(int seconds_cnt, bool include_days)
        {
            int rf_seconds = seconds_cnt % 60;
            seconds_cnt /= 60;
            int rf_minutes = seconds_cnt % 60;
            seconds_cnt /= 60;
            int rf_hours = seconds_cnt % 24;
            int rf_days = seconds_cnt / 24;
            String rf_timeofday = "";
            if (include_days)
                rf_timeofday = rf_days.ToString() + " ";
            if (rf_hours < 10)
                rf_timeofday += "0";
            rf_timeofday += rf_hours.ToString() + ":";
            if (rf_minutes < 10)
                rf_timeofday += "0";
            rf_timeofday += rf_minutes.ToString() + ":";
            if (rf_seconds < 10)
                rf_timeofday += "0";
            rf_timeofday += rf_seconds.ToString();
            return rf_timeofday;
        }

        private int CountColonsInString(String msg)
        {
            int i;
            int cnt = 0;
            for (i = 0; i < msg.Length; i++)
            {
                if (msg.ElementAt(i) == ',')
                    cnt++;
            }
            return cnt;
        }

        private bool CheckMbusCRC(byte[] dataBlock, int blockLength, short msg_crc)
        {
            // mbus data block is max 16 bytes
            if ((blockLength <= 0) || (blockLength > 16))
                return false;
            return (msg_crc == CRC16_0x3D65_normal(dataBlock, blockLength, 0, -1));
        }

        private short CRC16_0x3D65_normal(byte[] dataBlock, int blockLength, short init, short xor)
        {
            short crc = init;
            byte d, s, t;
            int i;

            for (i = 0; i < blockLength; i++)
            {
                d = dataBlock[i];
                s = (byte)((crc >> 8) ^ d);
                t = (byte)((s >> 5) ^ (s >> 4) ^ (s >> 3) ^ s);
                crc = (short)((crc <<  8) ^
                              (t        ) ^
                              (t   <<  2) ^
                              (t   <<  5) ^
                              (t   <<  6) ^
                              (t   <<  8) ^
                              (t   << 10) ^
                              (t   << 11) ^
                              (t   << 12) ^
                              (t   << 13));
            }
            return (short)(crc ^ xor);
        }

        private bool CheckFixedNumber(KeyEventArgs e)
        {
            bool Numeric = false;
            if ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ||
                (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) ||
                (e.KeyCode == Keys.Back))
            {
                Numeric = true;
            }
            return Numeric;
        }

        private bool CheckFloatNumber(KeyEventArgs e)
        {
            bool Numeric = false;
            if (e.KeyCode == Keys.OemPeriod || e.KeyCode == Keys.Oemcomma)
                Numeric = true;
            else
                Numeric = CheckFixedNumber(e);
            return Numeric;
        }

        private void textBoxFixedNr_KeyDown(object sender, KeyEventArgs e)
        {
            numberEntered = CheckFixedNumber(e);
        }

        private void textBoxFixedNr_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!numberEntered)
            {
                // Stop the character from being entered into the control since it is non-numerical.
                e.Handled = true;
            }
        }

        private void textBoxFloatNr_KeyDown(object sender, KeyEventArgs e)
        {
            numberEntered = CheckFloatNumber(e);
        }

        private void textBoxFloatNr_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!numberEntered)
            {
                e.Handled = true;
            }
        }

        // *****************************************************************
        // Tab: View all
        // *****************************************************************

        private int CheckAndAddIfNewPlugmeter(int pm_id)
        {
            int plugmeter = 0;
            int i;
            for (i = 0; i<max_plug_meters; i++)
            {
                if ((pmArray[i].uniqueId == 0) || (pmArray[i].uniqueId == pm_id))
                {
                    pmArray[i].uniqueId = pm_id;
                    plugmeter = i + 1;
                    if (plugmeter > numberOfPlugmeters)
                    {
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[5].Value = "";
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[6].Value = "";
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[8].Value = "";
                        for (; numberOfPlugmeters < plugmeter; numberOfPlugmeters++)
                        {
                            dataGridViewAll.Rows.Add();
                            dataGridViewAll.Rows[numberOfPlugmeters].Cells[0].Value = numberOfPlugmeters + 1;
                            dataGridViewAll.Rows[numberOfPlugmeters].Cells[1].Value = "";
                            dataGridViewAll.Rows[numberOfPlugmeters].Cells[2].Value = "No";
                        }
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[0].Value = "";
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[1].Value = "Total";
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[2].Value = "0";
                        UpdateTotals();
                    }
                    break;
                }
            }
            return plugmeter;
        }

        private int GetNumberOfOnAirMeters()
        {
            int i;
            int count = 0;
            for (i = 0; i < numberOfPlugmeters; i++)
            {
                if (pmArray[i].plugmeterOnAir)
                    count += 1;
            }
            return count;
        }

        private void timerTestOffAir_Tick(object sender, EventArgs e)
        {
            int plugmeter;
            for (plugmeter = 1; plugmeter <= numberOfPlugmeters; plugmeter++)
            {
                pmArray[plugmeter - 1].plugmeterOffAirCnt += 1;
                if (pmArray[plugmeter - 1].plugmeterOffAirCnt > ((pmArray[plugmeter - 1].transmitInterval * 2) + 1))
                {
                    // plugmeter must be off air
                    pmArray[plugmeter - 1].plugmeterOnAir = false;
                    if (firstSerialPort.IsOpen)
                    {
                        dataGridViewAll.Rows[plugmeter - 1].Cells[2].Value = "No";
                        dataGridViewAll.Rows[numberOfPlugmeters].Cells[2].Value = GetNumberOfOnAirMeters().ToString();
                        UpdateTotals();
                    }
                    UpdateChartPowerUsage(plugmeter, (float)0.0);
                    if (plugmeter == SelectedPlugmeter())
                        UpdatePMViewOnAirStatus(plugmeter);
                }
            }
        }

        private void SetOnAirStatus(int plugmeter)
        {
            pmArray[plugmeter - 1].plugmeterOffAirCnt = 0;
            if (!pmArray[plugmeter - 1].plugmeterOnAir)
            {
                pmArray[plugmeter - 1].plugmeterOnAir = true;
                pmArray[plugmeter - 1].name = GetNameFromXml(pmArray[plugmeter - 1].uniqueId);
                SetSerieNameChartPowerUsage(plugmeter, pmArray[plugmeter - 1].name);
                if (firstSerialPort.IsOpen)
                {
                    dataGridViewAll.Rows[plugmeter - 1].Cells[2].Value = "Yes";
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[2].Value = GetNumberOfOnAirMeters().ToString();
                }
                UpdateChartPowerUsage(plugmeter, (float)0.0);
            }
        }

        // *****************************************************************
        // Tab: Graph view
        // *****************************************************************

        // NOTE:
        //   For now only the first 8 plugmeters will have their power usage plotted!!!!!

        private void buttonClearGraph_Click(object sender, EventArgs e)
        {
            int plugmeter;
            for (plugmeter = 1; plugmeter <= 8; plugmeter++)
            {
                chartPowerUsage.Series[plugmeter - 1].Points.Clear();
            }
        }

        private void SetSerieNameChartPowerUsage(int plugmeter, String name)
        {
            if ((plugmeter > 0) && (plugmeter <= 8))
            {
                try
                {
                    if (name == "")
                    {
                        chartPowerUsage.Series[plugmeter - 1].Name = "Plugmeter " + plugmeter.ToString();
                    }
                    else
                    {
                        chartPowerUsage.Series[plugmeter - 1].Name = name;
                    }
                }
                catch (ArgumentException) { }
            }
        }

        private void ResetChartPowerUsage()
        {
            // set starting interval of power usage chart to 10 minutes
            domainUpDownZoom.SelectedIndex = 6;
            SetIntervalChartPowerUsage();
            int plugmeter;
            for (plugmeter = 1; plugmeter <= 8; plugmeter++)
            {
                SetSerieNameChartPowerUsage(plugmeter, "");
                chartPowerUsage.Series[plugmeter - 1].Points.Clear();
            }
        }

        private void domainUpDownZoom_SelectedItemChanged(object sender, EventArgs e)
        {
            SetIntervalChartPowerUsage();
        }

        private void SetIntervalChartPowerUsage()
        {
            int IntervalInSecs;
            switch (domainUpDownZoom.SelectedIndex)
            {
                case 0:       // 24 hours
                    IntervalInSecs = 60 * 60 * 24;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 6;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 24;
                    break;
                case 1:       // 12 hours
                    IntervalInSecs = 60 * 60 * 12;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 3;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 12;
                    break;
                case 2:       // 8 hours
                    IntervalInSecs = 60 * 60 * 8;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 2;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 8;
                    break;
                case 3:       // 4 hours
                    IntervalInSecs = 60 * 60 * 4;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 4;
                    break;
                case 4:       // 1 hour
                    IntervalInSecs = 60 * 60 * 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 4;
                    break;
                case 5:       // 30 minutes
                    IntervalInSecs = 60 * 30;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 6;
                    break;
                case 6:       // 10 minutes
                    IntervalInSecs = 60 * 10;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 10;
                    break;
                case 7:       // 5 minutes
                    IntervalInSecs = 60 * 5;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 5;
                    break;
                case 8:       // 1 minute
                default:      // 1 minute
                    IntervalInSecs = 60 * 1;
                    chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval = IntervalInSecs / 2;
                    chartPowerUsage.ChartAreas[0].AxisX.MinorGrid.Interval = IntervalInSecs / 12;
                    break;
            }
            chartPowerUsage.ChartAreas[0].AxisX.Interval = IntervalInSecs;
            chartPowerUsage.ChartAreas[0].AxisX.MajorTickMark.Interval = chartPowerUsage.ChartAreas[0].AxisX.MajorGrid.Interval;
            chartPowerUsage.ChartAreas[0].AxisX.ScaleView.Size = IntervalInSecs;
        }

        private void UpdateChartPowerUsage(int plugmeter, float Yvalue)
        {
            if ((plugmeter > 0) && (plugmeter <= 8))
            {
                TimeSpan t = (DateTime.UtcNow - firstSerialPortOpenTime);
                chartPowerUsage.Series[plugmeter - 1].Points.AddXY((int)t.TotalSeconds, Yvalue);
                if (domainUpDownZoom.SelectedIndex >= 7)
                {
                    if (chartPowerUsage.ChartAreas[0].AxisX.ScaleView.Position > (int)t.TotalSeconds - ((10 * chartPowerUsage.ChartAreas[0].AxisX.ScaleView.Size) / 9))
                    {
                        chartPowerUsage.ChartAreas[0].AxisX.ScaleView.Position = ((int)t.TotalSeconds - chartPowerUsage.ChartAreas[0].AxisX.ScaleView.Size);
                    }
                }
                // delete samples older then 24 hours
                if (chartPowerUsage.Series[plugmeter - 1].Points.Count > (60 * 60 * 24))
                {
                    chartPowerUsage.Series[plugmeter - 1].Points.Remove(chartPowerUsage.Series[plugmeter - 1].Points.First());
                }
            }
        }

        // *****************************************************************
        // Tab: Plugmeter view
        // *****************************************************************

        private int SelectedPlugmeter()
        {
            int plugmeter = 1;
            if (radioButtonPM2.Checked) plugmeter = 2;
            if (radioButtonPM3.Checked) plugmeter = 3;
            if (radioButtonPM4.Checked) plugmeter = 4;
            if (radioButtonPM5.Checked) plugmeter = 5;
            if (radioButtonPM6.Checked) plugmeter = 6;
            if (radioButtonPM7.Checked) plugmeter = 7;
            if (radioButtonPM8.Checked) plugmeter = 8;
            if (radioButtonPM9.Checked) plugmeter = 9;
            if (radioButtonPM0.Checked) plugmeter = 10;
            if (radioButtonPM10.Checked) plugmeter += 10;
            if (radioButtonPM20.Checked) plugmeter += 20;
            if (radioButtonPM30.Checked) plugmeter += 30;
            if (radioButtonPM40.Checked) plugmeter += 40;
            return plugmeter;
        }

        private void dataGridViewAll_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            int i;
            if (firstSerialPort.IsOpen)
            {
                for (i = 0; i < numberOfPlugmeters; i++)
                {
                    if (pmArray[i].uniqueId == 0)
                    {
                        pmArray[i].name = "";
                        dataGridViewAll.Rows[i].Cells[1].Value = "";
                    }
                    else
                    {
                        try
                        {
                            pmArray[i].name = dataGridViewAll.Rows[i].Cells[1].Value.ToString();
                        }
                        catch (NullReferenceException)
                        {
                            pmArray[i].name = "";
                        }
                        SetSerieNameChartPowerUsage(i + 1, pmArray[i].name);
                        AddOrChangeNameInXml(pmArray[i].uniqueId, pmArray[i].name);
                    }
                }
                RefreshPlugMeterView();
            }
            else
            {
                for (i = 0; i < numberOfPlugmeters; i++)
                {
                    dataGridViewAll.Rows[i].Cells[1].Value = "";
                }
            }
        }

        private void RefreshPlugMeterView()
        {
            int plugmeter = SelectedPlugmeter();
            if (firstSerialPort.IsOpen)
            {
                textBoxPMname.Text = pmArray[plugmeter - 1].name;
                textBoxTransmitInterval.Text = pmArray[plugmeter - 1].transmitInterval.ToString();
                if (pmArray[plugmeter - 1].mainsFrequency == 0)
                    textBoxFreq.Text = "";
                else
                    textBoxFreq.Text = pmArray[plugmeter - 1].mainsFrequency.ToString();
                textBoxVoltage.Text = pmArray[plugmeter - 1].md.V.fval.ToString("F3");
                textBoxCurrent.Text = pmArray[plugmeter - 1].md.I.fval.ToString("F3");
                textBoxP.Text = pmArray[plugmeter - 1].md.P.fval.ToString("F3");
                textBoxQ1.Text = pmArray[plugmeter - 1].md.Q1.fval.ToString("F3");
                textBoxS.Text = pmArray[plugmeter - 1].md.S.fval.ToString("F3");
                textBoxS1.Text = pmArray[plugmeter - 1].md.S1.fval.ToString("F3");
                textBoxPF.Text = pmArray[plugmeter - 1].md.PF.fval.ToString("F2");
                textBoxPF1.Text = pmArray[plugmeter - 1].md.PF1.fval.ToString("F2");
                textBoxSN.Text = pmArray[plugmeter - 1].md.SN.fval.ToString("F3");
                textBoxN.Text = pmArray[plugmeter - 1].md.N.fval.ToString("F3");
                textBoxTHDI.Text = pmArray[plugmeter - 1].md.THDI.fval.ToString("F3");
                textBoxTplus.Text = pmArray[plugmeter - 1].md.Tplus.fval.ToString("F3");
                textBoxTminus.Text = pmArray[plugmeter - 1].md.Tminus.fval.ToString("F3");
                textBoxOnTime.Text = Secs2timeofday(pmArray[plugmeter - 1].md.ontime, true);
            }
            else
            {
                textBoxPMname.Text = "";
                textBoxTransmitInterval.Text = "";
                textBoxFreq.Text = "";
                textBoxVoltage.Text = "";
                textBoxCurrent.Text = "";
                textBoxP.Text = "";
                textBoxQ1.Text = "";
                textBoxS.Text = "";
                textBoxS1.Text = "";
                textBoxPF.Text = "";
                textBoxPF1.Text = "";
                textBoxSN.Text = "";
                textBoxN.Text = "";
                textBoxTHDI.Text = "";
                textBoxTplus.Text = "";
                textBoxTminus.Text = "";
                textBoxOnTime.Text = "";
            }
            UpdatePMViewRelayStatus(plugmeter);
            UpdatePMViewOnAirStatus(plugmeter);
        }

        private void radioButtonPM1_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM1.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM2.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM3_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM3.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM4_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM4.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM5_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM5.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM6_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM6.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM7_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM7.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM8_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM8.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM9_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM9.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM0_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM0.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM00_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM00.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM10_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM10.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM20_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM20.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM30_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM30.Checked)
                RefreshPlugMeterView();
        }

        private void radioButtonPM40_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonPM40.Checked)
                RefreshPlugMeterView();
        }

        private void buttonRelayOpen_Click(object sender, EventArgs e)
        {
            PlugmeterCommand("pm", SelectedPlugmeter(), "relay", "open");
        }

        private void buttonRelayClose_Click(object sender, EventArgs e)
        {
            PlugmeterCommand("pm", SelectedPlugmeter(), "relay", "close");
        }

        private void textBoxTransmitInterval_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (textBoxTransmitInterval.TextLength > 0)
                {
                    int plugmeter = SelectedPlugmeter();
                    if (pmArray[plugmeter - 1].hwVersion > 2)
                    {
                        PlugmeterCommand("pm", plugmeter, "txtime", textBoxTransmitInterval.Text);
                        textBoxTransmitInterval.Text = "";
                    }
                    else
                        textBoxTransmitInterval.Text = pmArray[plugmeter - 1].transmitInterval.ToString();
                }
            }
            numberEntered = CheckFixedNumber(e);
        }

        private void textBoxTransmitInterval_Leave(object sender, EventArgs e)
        {
            int plugmeter = SelectedPlugmeter();
            textBoxTransmitInterval.Text = pmArray[plugmeter - 1].transmitInterval.ToString();
        }

        private void UpdatePMViewOnAirStatus(int plugmeter)
        {
            if (firstSerialPort.IsOpen)
            {
                if (pmArray[plugmeter - 1].plugmeterOnAir)
                {
                    textBoxOffAir.Text = "ON AIR";
                    textBoxOffAir.BackColor = Color.FromArgb(255, 207, 0);
                }
                else
                {
                    textBoxOffAir.Text = "OFF AIR";
                    textBoxOffAir.BackColor = Color.FromArgb(227, 0, 74);
                }
            }
            else
            {
                textBoxOffAir.Text = "";
                textBoxOffAir.BackColor = Color.White;
            }
        }

        private void UpdatePMViewRelayStatus(int plugmeter)
        {
            if (firstSerialPort.IsOpen && (pmArray[plugmeter - 1].hwVersion > 2))
            {
                if (pmArray[plugmeter - 1].relayClosed)
                    textBoxRelay.Text = "On";
                else
                    textBoxRelay.Text = "Off";
            }
            else
                textBoxRelay.Text = "";
        }

        // *****************************************************************
        // Tab: Logging view
        // *****************************************************************

        private bool loggingToScreen = false;
        private bool loggingShowTime = false;
        private int loggingLineCnt = 0;
        private Byte[] loggingByteArray = new Byte[1024];

        private void WriteLineToLogFile(String msg)
        {
            /*
            if (StatusBarFileName.Enabled)
            {
                int count = Encoding.Default.GetBytes(msg, 0, msg.Length, loggingByteArray, 0);
                loggingfs.Write(loggingByteArray, 0, count);
                loggingByteArray[0] = (Byte)'\n';
                loggingfs.Write(loggingByteArray, 0, 1);
            }
             * //*/
        }

        private void UpdateTotals()
        {
            /*
            if (firstSerialPort.IsOpen)
            {
                // sum the colums P, +T and -T
                try
                {
                    float P_total = (float)0.0;
                    float Tp_total = (float)0.0;
                    float Tm_total = (float)0.0;
                    int i;
                    for (i = 0; i < numberOfPlugmeters; i++)
                    {
                        if (pmArray[i].plugmeterOnAir)
                        {
                            P_total += pmArray[i].md.P.fval;
                            Tp_total += pmArray[i].md.Tplus.fval;
                            Tm_total += pmArray[i].md.Tminus.fval;
                        }
                    }
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[1].Value = "Total";
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[5].Value = P_total.ToString("F3");
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[6].Value = Tp_total.ToString("F3");
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[7].Value = (Tp_total * float.Parse(FormCost.ConsumedPrice) * (float)0.01).ToString("F3");
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[8].Value = Tm_total.ToString("F3");
                    dataGridViewAll.Rows[numberOfPlugmeters].Cells[9].Value = (Tm_total * float.Parse(FormCost.ProducedPrice) * (float)0.01).ToString("F3");
                }
                catch (ArgumentOutOfRangeException) { }
            }
              //*/
        }

        private void LoggingAddText(String msg)
        {
            /*
            if (loggingToScreen)
            {
                // allow maximum 1000 lines in textbox
                if (loggingLineCnt >= 1000)
                {
                    // delete first line in the textbox
                    int firstEolIndex = 0;
                    bool eolFound = false;
                    while (!eolFound)
                    {
                        textBoxLogging.Select(firstEolIndex, 2);
                        if (textBoxLogging.SelectedText == "\r\n")
                            eolFound = true;
                        else
                            firstEolIndex++;
                    }
                    textBoxLogging.Select(0, firstEolIndex + 2);
                    textBoxLogging.SelectedText = "";
                }
                else
                    loggingLineCnt++;
                if (loggingShowTime)
                    textBoxLogging.Text += DateTime.Now + "   ";
                textBoxLogging.AppendText(msg);
                textBoxLogging.AppendText("\r\n");
                textBoxLogging.Select(textBoxLogging.TextLength, 0);
                textBoxLogging.ScrollToCaret();
            }
             * //*/
        }

        private void buttonStartLogging_Click(object sender, EventArgs e)
        {
            /*
            if (loggingToScreen)
            {
                LoggingAddText("Logging to screen stopped");
                loggingToScreen = false;
                buttonStartLogging.Text = "Start";
            }
            else
            {
                loggingToScreen = true;
                LoggingAddText("Logging to screen started");
                buttonStartLogging.Text = "Stop";
            }
             * //*/
        }

        private void buttonClearLog_Click(object sender, EventArgs e)
        {
            /*
            textBoxLogging.Clear();
            loggingLineCnt = 0;
             * //*/
        }

        private void checkBoxShowTime_CheckedChanged(object sender, EventArgs e)
        {
            /*
            loggingShowTime = checkBoxShowTime.Checked;
             * 
             * //*/
        }

        // *****************************************************************
        // Tab: Control
        // *****************************************************************
//*
        private void ControlAddText(String msg)
        {
      //      textBoxControl.AppendText(msg);
      //      if (!msg.StartsWith(">") && !msg.StartsWith("$") && !msg.StartsWith("."))
      //          textBoxControl.AppendText("\r\n");
      //      textBoxControl.Select(textBoxControl.TextLength, 0);
      //      textBoxControl.ScrollToCaret();
        }

        private void buttonHelp_Click(object sender, EventArgs e)
        {
            DongleCommand("help");
        }
//*/
        // *****************************************************************
        // Tab: Maintenance
        // *****************************************************************

        private bool testingBusy = false;
        private int testingSwitchCounter = 0;
        private int testingMaxSwitches = 0;

        private int SelectedConfigPlugmeter()
        {
            /*
            int plugmeter = 1;
            if (radioButtonCVPM2.Checked) plugmeter = 2;
            if (radioButtonCVPM3.Checked) plugmeter = 3;
            if (radioButtonCVPM4.Checked) plugmeter = 4;
            if (radioButtonCVPM5.Checked) plugmeter = 5;
            if (radioButtonCVPM6.Checked) plugmeter = 6;
            if (radioButtonCVPM7.Checked) plugmeter = 7;
            if (radioButtonCVPM8.Checked) plugmeter = 8;
            if (radioButtonCVPM9.Checked) plugmeter = 9;
            if (radioButtonCVPM0.Checked) plugmeter = 10;
            if (radioButtonCVPM10.Checked) plugmeter += 10;
            if (radioButtonCVPM20.Checked) plugmeter += 20;
            if (radioButtonCVPM30.Checked) plugmeter += 30;
            if (radioButtonCVPM40.Checked) plugmeter += 40;
            return plugmeter;
            //*/
            return 1;
        }

        private void RefreshConfigurationValues(bool factory_defaults)
        {
            /*
            int plugmeter = SelectedConfigPlugmeter();
            if (factory_defaults)
            {
                float Vpp  = (float)0.0; // Todo: get from ini/config file ??
                float I1pp = (float)0.0; // Todo: get from ini/config file ??
                float I2pp = (float)0.0; // Todo: get from ini/config file ??
                float Phi1 = (float)0.0; // Todo: get from ini/config file ??
                float Phi2 = (float)0.0; // Todo: get from ini/config file ??
                textBoxVpp.Text  = Vpp.ToString();
                textBoxI1pp.Text = I1pp.ToString();
                textBoxI2pp.Text = I2pp.ToString();
                textBoxPhi1.Text = Phi1.ToString();
                textBoxPhi2.Text = Phi2.ToString();
            }
            else
            {
                if (firstSerialPort.IsOpen)
                {
                    textBoxVpp.Text  = pmArray[plugmeter - 1].Vpp.fval.ToString();
                    textBoxI1pp.Text = pmArray[plugmeter - 1].I1pp.fval.ToString();
                    textBoxI2pp.Text = pmArray[plugmeter - 1].I2pp.fval.ToString();
                    textBoxPhi1.Text = pmArray[plugmeter - 1].Phi1.fval.ToString();
                    textBoxPhi2.Text = pmArray[plugmeter - 1].Phi2.fval.ToString();
                }
                else
                {
                    textBoxVpp.Text  = "";
                    textBoxI1pp.Text = "";
                    textBoxI2pp.Text = "";
                    textBoxPhi1.Text = "";
                    textBoxPhi2.Text = "";
                }
            }
             * //*/
        }

        private void EnableTestGuiElements()
        {
            /*
            groupBoxCVPlugmeter.Enabled = !testingBusy;
            groupBoxCVConfig.Enabled = !testingBusy;
            textBoxTimeInterval.Enabled = !testingBusy;
            textBoxMaxSwitchCount.Enabled = !testingBusy;
            timerTestSwitching.Enabled = testingBusy;
             //*/
        }

        private void radioButtonCVPM1_CheckedChanged(object sender, EventArgs e)
        {
            /*
            if (radioButtonCVPM1.Checked)
                RefreshConfigurationValues(false);
             * //*/
        }

        private void radioButtonCVPM2_CheckedChanged(object sender, EventArgs e)
        {
            /*
            if (radioButtonCVPM2.Checked)
                RefreshConfigurationValues(false);
             * //*/
        }

        private void radioButtonCVPM3_CheckedChanged(object sender, EventArgs e)
        {
             /*
            if (radioButtonCVPM3.Checked)
                RefreshConfigurationValues(false);
              * //*/
        }
/*
        private void radioButtonCVPM4_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM4.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM5_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM5.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM6_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM6.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM7_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM7.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM8_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM8.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM9_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM9.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM0_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM0.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM00_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM00.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM10_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM10.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM20_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM20.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM30_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM30.Checked)
                RefreshConfigurationValues(false);
        }

        private void radioButtonCVPM40_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonCVPM40.Checked)
                RefreshConfigurationValues(false);
        }

        private void buttonGet_Click(object sender, EventArgs e)
        {
            RefreshConfigurationValues(false);
            PlugmeterCommand("pm", SelectedConfigPlugmeter(), "config");
        }

        private void buttonSet_Click(object sender, EventArgs e)
        {
            IntFloatUnion Vpp;
            IntFloatUnion I1pp;
            IntFloatUnion I2pp;
            IntFloatUnion Phi1;
            IntFloatUnion Phi2;
            Vpp.ival = 0;
            Vpp.fval = float.Parse(textBoxVpp.Text);
            String parm1 = Vpp.ival.ToString("X8");
            I1pp.ival = 0;
            I1pp.fval = float.Parse(textBoxI1pp.Text);
            String parm2 = I1pp.ival.ToString("X8");
            I2pp.ival = 0;
            I2pp.fval = float.Parse(textBoxI2pp.Text);
            String parm3 = I2pp.ival.ToString("X8");
            Phi1.ival = 0;
            Phi1.fval = float.Parse(textBoxPhi1.Text);
            String parm4 = Phi1.ival.ToString("X8");
            Phi2.ival = 0;
            Phi2.fval = float.Parse(textBoxPhi2.Text);
            String parm5 = Phi2.ival.ToString("X8");
            PlugmeterCommand("pm", SelectedConfigPlugmeter(), "config", parm1, parm2, parm3, parm4, parm5);
        }

        private void buttonReset_Click(object sender, EventArgs e)
        {
            RefreshConfigurationValues(true);
        }

        private void buttonStore_Click(object sender, EventArgs e)
        {
            PlugmeterCommand("pm", SelectedConfigPlugmeter(), "store");
        }

        private void buttonTestStart_Click(object sender, EventArgs e)
        {
            if (!testingBusy)
                TestStart();
            else
                TestStop();
        }

        private void TestSwitching()
        {
            testingSwitchCounter += 1;
            if (testingSwitchCounter <= testingMaxSwitches)
            {
                int plugmeter = SelectedConfigPlugmeter();
                String parm1;
                if (pmArray[plugmeter - 1].relayClosed)
                    parm1 = "open";
                else
                    parm1 = "close";
                PlugmeterCommand("pm", plugmeter, "relay", parm1);
                textBoxSwitchCounter.Text = testingSwitchCounter.ToString();
            }
            else
                TestStop();
        }

        private void timerTestSwitching_Tick(object sender, EventArgs e)
        {
            TestSwitching();
        }

        private void TestStart()
        {
            testingBusy = true;
            buttonTesting.Text = "Stop";
            testingSwitchCounter = 0;
            testingMaxSwitches = int.Parse(textBoxMaxSwitchCount.Text);
            timerTestSwitching.Interval = int.Parse(textBoxTimeInterval.Text) * 1000;
            EnableTestGuiElements();
            TestSwitching();
        }

        private void TestStop()
        {
            testingBusy = false;
            buttonTesting.Text = "Start";
            EnableTestGuiElements();
        }

        private void textBoxCommand_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
        //        ControlAddText(textBoxCommand.Text);
        //        WriteFirstSerial(textBoxCommand.Text);
        //        textBoxCommand.Text = "";
            }
        }
//*/
        // *****************************************************************
        // Tab: Calibration
        // *****************************************************************
/*
        private void tabCalibration_Enter(object sender, EventArgs e)
        {
            PlugmeterCommand("pm", SelectedCalibrationPlugmeter(), "config");
            RefreshCalibrationValues(false);
        }

        private int SelectedCalibrationPlugmeter()
        {
            int plugmeter = 1;
            if (RadioButtonCPM2.Checked) plugmeter = 2;
            if (RadioButtonCPM3.Checked) plugmeter = 3;
            if (RadioButtonCPM4.Checked) plugmeter = 4;
            if (RadioButtonCPM5.Checked) plugmeter = 5;
            if (RadioButtonCPM6.Checked) plugmeter = 6;
            if (RadioButtonCPM7.Checked) plugmeter = 7;
            if (RadioButtonCPM8.Checked) plugmeter = 8;
            if (RadioButtonCPM9.Checked) plugmeter = 9;
            if (RadioButtonCPM0.Checked) plugmeter = 10;
            if (RadioButtonCPM10.Checked) plugmeter += 10;
            if (RadioButtonCPM20.Checked) plugmeter += 20;
            if (RadioButtonCPM30.Checked) plugmeter += 30;
            if (RadioButtonCPM40.Checked) plugmeter += 40;
            return plugmeter;
        }

        public void CalibrationCancel()
        {
            PlugmeterCommandForced("cm", SelectedCalibrationPlugmeter(), "cancel");
        }

        public void CalibrationPrevious()
        {
            PlugmeterCommand("cm", SelectedCalibrationPlugmeter(), "previous");
        }

        public void CalibrationNext()
        {
            PlugmeterCommand("cm", SelectedCalibrationPlugmeter(), "next");
        }

        public void CalibrationStore()
        {
            PlugmeterCommand("pm", SelectedCalibrationPlugmeter(), "store");
        }

        private void RefreshCalibrationValues(bool factory_defaults)
        {
            int plugmeter = SelectedCalibrationPlugmeter();
            if (factory_defaults)
            {
                float Vpp = (float)0.0; // Todo: get from ini/config file ??
                float I1pp = (float)0.0; // Todo: get from ini/config file ??
                float I2pp = (float)0.0; // Todo: get from ini/config file ??
                float Phi1 = (float)0.0; // Todo: get from ini/config file ??
                float Phi2 = (float)0.0; // Todo: get from ini/config file ??
                textBoxCVpp.Text = Vpp.ToString("F3");
                textBoxCI1pp.Text = I1pp.ToString("F3");
                textBoxCI2pp.Text = I2pp.ToString("F3");
                textBoxCDP1.Text = Phi1.ToString("F6");
                textBoxCDP2.Text = Phi2.ToString("F6");
            }
            else
            {
                if (firstSerialPort.IsOpen)
                {
                    textBoxCVpp.Text = pmArray[plugmeter - 1].Vpp.fval.ToString("F3");
                    textBoxCI1pp.Text = pmArray[plugmeter - 1].I1pp.fval.ToString("F3");
                    textBoxCI2pp.Text = pmArray[plugmeter - 1].I2pp.fval.ToString("F3");
                    textBoxCDP1.Text = pmArray[plugmeter - 1].Phi1.fval.ToString("F6");
                    textBoxCDP2.Text = pmArray[plugmeter - 1].Phi2.fval.ToString("F6");
                    if (pmArray[plugmeter - 1].mainsFrequency == 50)
                    {
                        textBoxCVref.Text = CalibrationRef50Data.Vref.fval.ToString("F3");
                        textBoxCI1ref.Text = CalibrationRef50Data.I1ref.fval.ToString("F3");
                        textBoxCI2ref.Text = CalibrationRef50Data.I2ref.fval.ToString("F3");
                    }
                    else if (pmArray[plugmeter - 1].mainsFrequency == 60)
                    {
                        textBoxCVref.Text = CalibrationRef60Data.Vref.fval.ToString("F3");
                        textBoxCI1ref.Text = CalibrationRef60Data.I1ref.fval.ToString("F3");
                        textBoxCI2ref.Text = CalibrationRef60Data.I2ref.fval.ToString("F3");
                    }
                    else
                    {
                        textBoxCVref.Text = "";
                        textBoxCI1ref.Text = "";
                        textBoxCI2ref.Text = "";
                    }
                }
                else
                {
                    textBoxCVpp.Text = "";
                    textBoxCI1pp.Text = "";
                    textBoxCI2pp.Text = "";
                    textBoxCDP1.Text = "";
                    textBoxCDP2.Text = "";
                    textBoxCVref.Text = "";
                    textBoxCI1ref.Text = "";
                    textBoxCI2ref.Text = "";
                }
            }
            RefreshCalibrationView();
        }

        private void RefreshCalibrationView()
        {
            int plugmeter = SelectedCalibrationPlugmeter();
            if (firstSerialPort.IsOpen)
            {
                textBoxCName.Text = pmArray[plugmeter - 1].name;
                textBoxCV.Text = pmArray[plugmeter - 1].md.V.fval.ToString("F3");
                textBoxCI.Text = pmArray[plugmeter - 1].md.I.fval.ToString("F3");
                textBoxCP.Text = pmArray[plugmeter - 1].md.P.fval.ToString("F3");
                textBoxCQ1.Text = pmArray[plugmeter - 1].md.Q1.fval.ToString("F3");
            }
            else
            {
                textBoxCName.Text = "";
                textBoxCV.Text = "";
                textBoxCI.Text = "";
                textBoxCP.Text = "";
                textBoxCQ1.Text = "";
            }
//            UpdatePMViewOnAirStatus(plugmeter);
        }

        private void StartCalibrationButton_Click(object sender, EventArgs e)
        {
            int plugmeter = SelectedCalibrationPlugmeter();
            if (pmArray[plugmeter - 1].mainsFrequency != 0)
            {
                String parm1;
                String parm2;
                String parm3;
                String parm4;
                String parm5;
                String parm6;

                if (pmArray[plugmeter - 1].mainsFrequency == 50)
                {
                    parm1 = CalibrationRef50Data.Vpp.ival.ToString("X8");
                    parm2 = CalibrationRef50Data.I1pp.ival.ToString("X8");
                    parm3 = CalibrationRef50Data.I2pp.ival.ToString("X8");
                    parm4 = CalibrationRef50Data.Vref.ival.ToString("X8");
                    parm5 = CalibrationRef50Data.I1ref.ival.ToString("X8");
                    parm6 = CalibrationRef50Data.I2ref.ival.ToString("X8");
                }
                else
                {
                    parm1 = CalibrationRef60Data.Vpp.ival.ToString("X8");
                    parm2 = CalibrationRef60Data.I1pp.ival.ToString("X8");
                    parm3 = CalibrationRef60Data.I2pp.ival.ToString("X8");
                    parm4 = CalibrationRef60Data.Vref.ival.ToString("X8");
                    parm5 = CalibrationRef60Data.I1ref.ival.ToString("X8");
                    parm6 = CalibrationRef60Data.I2ref.ival.ToString("X8");
                }
                PlugmeterCommand("cm", plugmeter, "start", parm1, parm2, parm3, parm4, parm5, parm6);
                DialogCalibration.ShowDialog();
            }
        }

        private void RadioButtonCPM1_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM1.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM2_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM2.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM3_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM3.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM4_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM4.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM5_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM5.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM6_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM6.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM7_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM7.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM8_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM8.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM9_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM0.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM0_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM0.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM00_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM00.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM10_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM10.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM20_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM20.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM30_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM30.Checked)
                RefreshCalibrationValues(false);
        }

        private void RadioButtonCPM40_CheckedChanged(object sender, EventArgs e)
        {
            if (RadioButtonCPM40.Checked)
                RefreshCalibrationValues(false);
        }
//*/
        // *****************************************************************
        // Tab: Sniffer
        // *****************************************************************

        private bool sniffingStarted = false;
        private int snifferLineCnt = 0;

        private void EnableSniffingGuiElements()
        {
            groupBoxPlugmeter.Enabled = !sniffingStarted;
            groupBoxRelay.Enabled = !sniffingStarted;
            groupBoxTransmitInterval.Enabled = !sniffingStarted;
            groupBoxReadings.Enabled = !sniffingStarted;
    //        textBoxCommand.Enabled = !sniffingStarted;
     //       buttonHelp.Enabled = !sniffingStarted;
      //      groupBoxCVPlugmeter.Enabled = !sniffingStarted;
       //     groupBoxCVConfig.Enabled = !sniffingStarted;
        //    groupBoxRelayTest.Enabled = !sniffingStarted;
            groupBoxChipRate.Enabled = sniffingStarted;
        }

        private void SniffingAddText(String msg, Color msgColor)
        {
            if (sniffingStarted)
            {
                // allow maximum 1000 lines in textbox
                if (snifferLineCnt >= 1000)
                {
                    // delete first line in the textbox
                    int firstEolIndex = 0;
                    bool eolFound = false;
                    while (!eolFound)
                    {
                        richTextBoxSniffer.Select(firstEolIndex, 1);
                        if (richTextBoxSniffer.SelectedText == "\n")
                            eolFound = true;
                        else
                            firstEolIndex++;
                    }
                    richTextBoxSniffer.Select(firstEolIndex + 1, 1);
                    string replaceString = richTextBoxSniffer.SelectedText;
                    richTextBoxSniffer.Select(0, firstEolIndex + 2);
                    richTextBoxSniffer.SelectedText = replaceString;
                }
                else
                    snifferLineCnt++;
                richTextBoxSniffer.SelectionColor = msgColor;
                richTextBoxSniffer.AppendText(msg);
                richTextBoxSniffer.AppendText("\n");
                richTextBoxSniffer.Select(richTextBoxSniffer.TextLength, 0);
                richTextBoxSniffer.ScrollToCaret();
            }
        }

        private void buttonSnifferStart_Click(object sender, EventArgs e)
        {
            if (!sniffingStarted)
                StartSniffing();
            else
            {
                StopSniffing();
            }
            EnableSniffingGuiElements();
        }

        private void StartSniffing()
        {
            sniffingStarted = true;
            buttonSnifferStart.Text = "Stop";
            DongleCommand("rx m");
            DongleCommand("start");
        }

        private void StopSniffing()
        {
            sniffingStarted = false;
            buttonSnifferStart.Text = "Start";
            radioButton100K.Checked = true;
            radioButton32K.Checked = false;
            textBoxCenterFrequency.Text = "868.950 MHz";
            textBoxEncoding.Text = "3 out of 6";
            DongleCommand("rf 100");
        }

        private void radioButton100K_CheckedChanged(object sender, EventArgs e)
        {
            textBoxCenterFrequency.Text = "868.950 MHz";
            textBoxEncoding.Text = "3 out of 6";
            DongleCommand("rf 100");
        }

        private void radioButton32K_CheckedChanged(object sender, EventArgs e)
        {
            textBoxCenterFrequency.Text = "868.300 MHz";
            textBoxEncoding.Text = "Manchester";
            DongleCommand("rf 32");
        }

        private void buttonSnifferClean_Click(object sender, EventArgs e)
        {
            richTextBoxSniffer.Clear();
            snifferLineCnt = 0;
        }
/*
        // *****************************************************************
        // Tab: Contact
        // *****************************************************************

        private void linkLabelNXP_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            linkLabelNXP.Links[linkLabelNXP.Links.IndexOf(e.Link)].Visited = true;

            string target = linkLabelNXP.Text;

            // If the value looks like a URL, navigate to it.
            if ((null != target) && (target.StartsWith("http://www.")))
            {
                System.Diagnostics.Process.Start(target);
            }
        }
//*/
        private void costToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = DialogCost.ShowDialog();
            if (result == DialogResult.OK)
            {
                XmlNodeList xmlnode = xmldoc.GetElementsByTagName("PRICING");
                for (int i = 0; i < xmlnode.Count; i++)
                {
                    for (int j = 0; j < xmlnode[i].ChildNodes.Count; j++)
                    {
                        if (xmlnode[i].ChildNodes[j].Name == "Consumed")
                        {
                            xmlnode[i].ChildNodes[j].InnerText = FormCost.ConsumedPrice;
                        }
                        else if (xmlnode[i].ChildNodes[j].Name == "Produced")
                        {
                            xmlnode[i].ChildNodes[j].InnerText = FormCost.ProducedPrice;
                        }
                    }
                }
                xmldoc.Save(xmlFile);
            }
        }
    }
}
